﻿using BCCommon;
using BCCommon.Enums;
using BCData.Trading.Purchase.GoodsPurchase;
using BCDto.Trading.Purchase.GoodsPurchase;
using BCEntity.Trading.Purchase.GoodsPurchase;
using BCEntity.Common.EntityNameConst;
using BCService.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BCCommon.TradingEnums;
using BCEntity.Trading.Purchase.GoodsPurchaseChecklist;
using BCData.Trading.Purchase.GoodsPurchaseChecklist;
using BCData.Trading.Purchase.GoodsPurchaseItem;
using Microsoft.Extensions.Configuration;
using BCService.Trading.Purchase.GoodsPurchasePaidRecord;
using BCService.Trading.Purchase.GoodsPurchaseContractAttachment;
using BCEntity.Trading.Purchase.GoodsPurchaseContractAttachment;
using BCDto.Trading.Purchase.GoodsPurchaseContractAttachment;
using BCDto.Sim.Admin.Admin;

namespace BCService.Trading.Purchase.GoodsPurchase
{
    public class GoodsPurchaseService : IGoodsPurchaseService
    {
        private readonly IDatabaseContext databaseContext;
        private readonly IConfiguration configuration;
        private readonly IRedisService redisService;
        private readonly IGoodsPurchaseData goodsPurchaseData;
        private readonly IGoodsPurchaseChecklistData goodsPurchaseChecklistData;
        private readonly IGoodsPurchaseItemData goodsPurchaseItemData;
        private readonly IGoodsPurchasePaidRecordService goodsPurchasePaidRecordService;
        private readonly IGoodsPurchaseContractAttachmentService goodsPurchaseContractAttachmentService;
        private readonly string key = string.Format("{0}", EntityNameConst.GoodsPurchaseEntity);

        public GoodsPurchaseService(IDatabaseContext databaseContext,
            IConfiguration configuration,
            IRedisService redisService,
            IGoodsPurchaseData goodsPurchaseData,
            IGoodsPurchaseChecklistData goodsPurchaseChecklistData,
            IGoodsPurchaseItemData goodsPurchaseItemData,
            IGoodsPurchasePaidRecordService goodsPurchasePaidRecordService,
            IGoodsPurchaseContractAttachmentService goodsPurchaseContractAttachmentService)
        {
            this.databaseContext = databaseContext;
            this.configuration = configuration;
            this.redisService = redisService;
            this.goodsPurchaseData = goodsPurchaseData;
            this.goodsPurchaseChecklistData = goodsPurchaseChecklistData;
            this.goodsPurchaseItemData = goodsPurchaseItemData;
            this.goodsPurchasePaidRecordService = goodsPurchasePaidRecordService;
            this.goodsPurchaseContractAttachmentService = goodsPurchaseContractAttachmentService;
        }

        #region 检查商品采购单是否存在
        public bool Exists(long goodsPurchaseId)
        {
            return this.goodsPurchaseData.Exists(goodsPurchaseId).GetAwaiter().GetResult();
        }
        #endregion

        #region 检查商品采购单是否存在
        public bool Exists(string goodsPurchaseNo)
        {
            return this.goodsPurchaseData.Exists(goodsPurchaseNo).GetAwaiter().GetResult();
        }
        #endregion

        #region 添加商品采购单
        public GoodsPurchaseDto Add(GoodsPurchaseAllRequestDto requestDto,AdminDto adminDto)
        {
            if (this.Exists(requestDto.GoodsPurchaseNo))
            {
                throw new ArgumentException("此采购单编号已存在!");
            }
            var entity = requestDto.As<GoodsPurchaseEntity>();
            entity.CreateAdminName = adminDto.FullName;
            entity.CreateAdminId = adminDto.AdminId;
            var checklistEntities = requestDto.Checklist.As<List<GoodsPurchaseChecklistEntity>>();
            foreach (var item in checklistEntities)
            {
                if (!this.goodsPurchaseItemData.Exists(item.GoodsPurchaseItemId).Result)
                {
                    throw new ArgumentException(string.Format("采购项Id：{0} 不存在!", item.GoodsPurchaseItemId));
                }
                if (item.PurchasePrice < 0)
                {
                    throw new ArgumentException(string.Format("采购项Id：{0} 采购单价不应为负数金额!", item.GoodsPurchaseItemId));
                }
                if (item.PurchaseAmount < 0)
                {
                    throw new ArgumentException(string.Format("采购项Id：{0} 采购总价不应为负数金额!", item.GoodsPurchaseItemId));
                }

                var purchaseItemEntity = this.goodsPurchaseItemData.GetEntity(item.GoodsPurchaseItemId).Result;
                item.SaleGoodsCategoryId = purchaseItemEntity.SaleGoodsCategoryId;
                item.CategoryName = purchaseItemEntity.CategoryName;
                item.SaleGoodsId = purchaseItemEntity.SaleGoodsId;
                item.GoodsName = purchaseItemEntity.GoodsName;
                item.Sku = purchaseItemEntity.Sku;
                item.SaleGoodsNormId = purchaseItemEntity.SaleGoodsNormId;
                item.NormName = purchaseItemEntity.NormName;
                item.NormNo = purchaseItemEntity.NormNo;
                item.VendorCategoryId = purchaseItemEntity.VendorCategoryId;
                item.VendorCategoryName = purchaseItemEntity.VendorCategoryName;
                item.VendorId = purchaseItemEntity.VendorId;
                item.VendorName = purchaseItemEntity.VendorName;
                item.PurchaseUnit = purchaseItemEntity.PurchaseUnit;
                item.PurchaseCount = purchaseItemEntity.PurchaseCount;
                item.CreateAdminName = adminDto.FullName;
                item.CreateAdminId = adminDto.AdminId;
                item.GoodsPurchaseNo = entity.GoodsPurchaseNo;
            }
            databaseContext.BeginTransaction();
            var result = this.goodsPurchaseData.Add(entity).GetAwaiter().GetResult();
            List<GoodsPurchaseChecklistEntity> checklist = new List<GoodsPurchaseChecklistEntity>();
            foreach (var item in checklistEntities)
            {
                item.GoodsPurchaseId = result.GoodsPurchaseId;
                checklist.Add(this.goodsPurchaseChecklistData.Add(item).Result);
                this.goodsPurchaseItemData.UpdateCreatedTask(item.GoodsPurchaseItemId).GetAwaiter().GetResult();
            }
            databaseContext.Commit();
            string itemKey = string.Format("{0}", EntityNameConst.GoodsPurchaseItemEntity);
            this.redisService.DeleteMultipleKey(itemKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<GoodsPurchaseDto>();
        }
        #endregion

        #region 修改商品采购单
        public GoodsPurchaseDto Update(GoodsPurchasePutDto putDto,AdminDto adminDto)
        {
            if (!this.Exists(putDto.GoodsPurchaseId))
            {
                throw new ArgumentException("此记录不存在!");
            }
            var dto = this.Get(putDto.GoodsPurchaseId);
            if (this.Exists(putDto.GoodsPurchaseNo))
            {
                if (dto.GoodsPurchaseNo != putDto.GoodsPurchaseNo)
                {
                    throw new ArgumentException("此采购单编号已存在!");
                }
            }

            if (dto.HandleTime.HasValue && dto.PaidDepositeAmount.HasValue && dto.PaidDepositeAmount.Value > 0)
            {
                throw new ArgumentException("此采购单已完成定金支付，无法再进行修改!");
            }
            if (bool.TryParse(configuration["EnabledWorkflow"], out bool enableWorkflow))
            {
                if (enableWorkflow && dto.PurchaseStatus != PurchaseStatusType.Ready)
                {
                    string message = "已启用工作流";
                    throw new ArgumentException(string.Format("此采购单{0}，无法再进行修改!", message));
                }
            }

            var entity = putDto.As<GoodsPurchaseEntity>();
            entity.EditAdminName = adminDto.FullName;
            entity.EditAdminId = adminDto.AdminId;
            var result = this.goodsPurchaseData.Update(entity).GetAwaiter().GetResult().As<GoodsPurchaseDto>();
            string itemKey = string.Format("{0}", EntityNameConst.GoodsPurchaseItemEntity);
            this.redisService.DeleteMultipleKey(itemKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result;
        }
        #endregion

        #region 删除商品采购单
        public bool Delete(long goodsPurchaseId)
        {
            if (!this.Exists(goodsPurchaseId))
            {
                throw new ArgumentException("此记录不存在!");
            }

            var result = this.goodsPurchaseData.Delete(goodsPurchaseId).GetAwaiter().GetResult();
            string itemKey = string.Format("{0}", EntityNameConst.GoodsPurchaseItemEntity);
            this.redisService.DeleteMultipleKey(itemKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result;
        }
        #endregion

        #region 获取商品采购单
        public GoodsPurchaseDto Get(long goodsPurchaseId)
        {
            string cacheKey = this.redisService.GetKey(key, goodsPurchaseId);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                var data = this.goodsPurchaseData.GetEntity(goodsPurchaseId).GetAwaiter().GetResult();
                return data;
            }, TimeSpan.FromMinutes(30));
            return result.As<GoodsPurchaseDto>();
        }
        #endregion

        #region 获取商品采购单分页
        public PageableList<GoodsPurchaseDto> Query(string purchaseNo, PurchaseInventoryStatusType? purchaseInventoryStatusType, PurchaseDateType? purchaseDateType, DateTime? start, DateTime? end, string sortName, bool? ascending, int pageIndex, int pageSize)
        {
            string cacheKey = this.redisService.GetKey(key, purchaseNo, purchaseInventoryStatusType, purchaseDateType, start, end, sortName, ascending, pageIndex, pageSize);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                var data = this.goodsPurchaseData.Query(purchaseNo, purchaseInventoryStatusType, purchaseDateType, start, end, sortName, ascending, pageIndex, pageSize).GetAwaiter().GetResult();
                return new PageableList<GoodsPurchaseDto>
                {
                    Count = data.Item2,
                    Items = data.Item1.As<IEnumerable<GoodsPurchaseDto>>(),
                    PageIndex = pageIndex,
                    PageSize = pageSize,
                    ServerTime = DateTime.Now
                };
            }, TimeSpan.FromMinutes(30));

            return result;
        }
        #endregion

        #region 修改采购单状态
        public bool UpdatePurchaseStatus(long goodsPurchaseId, PurchaseStatusType purchaseStatusType)
        {
            if (!this.Exists(goodsPurchaseId))
            {
                throw new ArgumentException("此采购单不存在!");
            }

            var dto = this.Get(goodsPurchaseId);
            if (bool.TryParse(configuration["EnabledWorkflow"], out bool enableWorkflow))
            {
                if (enableWorkflow && dto.PurchaseStatus != PurchaseStatusType.Ready)
                {
                    string message = "已启用工作流";
                    throw new ArgumentException(string.Format("此采购单{0}，无法再进行修改!", message));
                }
            }
            bool result = this.goodsPurchaseData.UpdatePurchaseStatus(goodsPurchaseId, purchaseStatusType).Result;
            this.redisService.DeleteMultipleKey(key,false);
            return result;
        }
        #endregion

        #region 修改定金支付信息
        public GoodsPurchaseDto UpdateDepositePaymentInfo(GoodsPurchaseDepositePaymentRequestDto requestDto)
        {
            if (!this.Exists(requestDto.GoodsPurchaseId))
            {
                throw new ArgumentException("此采购单不存在!");
            }
            var dto = this.Get(requestDto.GoodsPurchaseId);
            if (!dto.HasNotifyPurchaseManage)
            {
                throw new ArgumentException("此采购合同并未完成定金支付信息补充，请先完成定金支付信息补充!");
            }
            //if (dto.DepositePaymentDate.HasValue&&dto.PaidDepositeAmount.HasValue)
            //{
            //    throw new ArgumentException("此采购单定金支付信息已填写，无法修改!");
            //}
            databaseContext.BeginTransaction();
            var entity = requestDto.As<GoodsPurchaseEntity>();
            var result = this.goodsPurchaseData.UpdateDepositePaymentInfo(entity).Result;
            foreach (var item in requestDto.PaidRecords)
            {
                item.PaidType = PurchasePaidType.Deposite;
                this.goodsPurchasePaidRecordService.Add(item);
            }
            databaseContext.Commit();
            string cacheKey = this.redisService.GetSingleRootKey(key, "goodsPurchaseId", requestDto.GoodsPurchaseId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<GoodsPurchaseDto>();
        }
        #endregion

        #region 修改尾款支付信息
        public GoodsPurchaseDto UpdateLastPaymentInfo(GoodsPurchaseLastPaymentRequestDto requestDto)
        {
            if (!this.Exists(requestDto.GoodsPurchaseId))
            {
                throw new ArgumentException("此采购单不存在!");
            }
            var dto = this.Get(requestDto.GoodsPurchaseId);
            if (!dto.DepositePaymentDate.HasValue && !dto.PaidDepositeAmount.HasValue)
            {
                throw new ArgumentException("此采购单定金支付信息未填写，无法直接填写尾款支付信息，请先填写定金支付信息!");
            }
            databaseContext.BeginTransaction();
            var entity = requestDto.As<GoodsPurchaseEntity>();
            entity.PaidLastAmount = dto.PaidLastAmount + entity.PaidLastAmount;
            entity.LatestPaidLastAmount = entity.PaidLastAmount;
            var result = this.goodsPurchaseData.UpdateLastPaymentInfo(entity).Result;
            foreach (var item in requestDto.PaidRecords)
            {
                item.PaidType = PurchasePaidType.LastPayment;
                this.goodsPurchasePaidRecordService.Add(item);
            }
            databaseContext.Commit();
            string cacheKey = this.redisService.GetSingleRootKey(key, "goodsPurchaseId", requestDto.GoodsPurchaseId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<GoodsPurchaseDto>();
        }
        #endregion

        #region 更新商品采购交付信息
        public GoodsPurchaseDto UpdateDeliveryInfo(GoodsPurchaseDeliveryInfoRequestDto requestDto,AdminDto adminDto)
        {
            if (!this.Exists(requestDto.GoodsPurchaseId))
            {
                throw new ArgumentException("此采购单不存在!");
            }
            var dto = this.Get(requestDto.GoodsPurchaseId);

            if(dto.DeliveryDate.HasValue&&!string.IsNullOrWhiteSpace(dto.PurchaseContractNo))
            {
                throw new ArgumentException("此采购单已完成交付信息补充,无需重复操作!");
            }
            databaseContext.BeginTransaction();
            var entity = requestDto.As<GoodsPurchaseEntity>();

            var result = this.goodsPurchaseData.UpdateDeliveryInfo(entity).Result;
            foreach (var item in requestDto.Attachments)
            {
                GoodsPurchaseContractAttachmentRequestDto attachmentRequestDto = new GoodsPurchaseContractAttachmentRequestDto();
                attachmentRequestDto.GoodsPurchaseId = entity.GoodsPurchaseId;
                attachmentRequestDto.AttachmentAddress = item;
                this.goodsPurchaseContractAttachmentService.Add(attachmentRequestDto, adminDto);
            }
            databaseContext.Commit();
            string cacheKey = this.redisService.GetSingleRootKey(key, "goodsPurchaseId", requestDto.GoodsPurchaseId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<GoodsPurchaseDto>();
        }
        #endregion

        #region 修改采购暂停备注信息
        public GoodsPurchaseDto UpdateSuspendRemark(GoodsPurchaseRemarkRequestDto requestDto)
        {
            if (!this.Exists(requestDto.GoodsPurchaseId))
            {
                throw new ArgumentException("此采购单不存在!");
            }
            var dto = this.Get(requestDto.GoodsPurchaseId);
            if(dto.PurchaseStatus == PurchaseStatusType.Suspend)
            {
                throw new ArgumentException("此采购单已暂停，无需重复操作!");
            }

            var entity = dto.As<GoodsPurchaseEntity>();
            entity.SuspendRemark = requestDto.Remark;
            var result = this.goodsPurchaseData.UpdateSuspendRemark(entity).Result;
            string cacheKey = this.redisService.GetSingleRootKey(key, "goodsPurchaseId", requestDto.GoodsPurchaseId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<GoodsPurchaseDto>();
        }
        #endregion

        #region 修改采购暂停恢复备注信息
        public GoodsPurchaseDto UpdateRestoreRemark(GoodsPurchaseRemarkRequestDto requestDto)
        {
            if (!this.Exists(requestDto.GoodsPurchaseId))
            {
                throw new ArgumentException("此采购单不存在!");
            }
            var dto = this.Get(requestDto.GoodsPurchaseId);
            if (dto.PurchaseStatus != PurchaseStatusType.Suspend)
            {
                throw new ArgumentException("此采购单不在暂停中，无法执行此恢复操作!");
            }
            if (dto.PurchaseStatus == PurchaseStatusType.Stop)
            {
                throw new ArgumentException("此采购单已终止，无法执行此恢复操作!");
            }
            var entity = dto.As<GoodsPurchaseEntity>();
            entity.RestoreRemark = requestDto.Remark;
            var result = this.goodsPurchaseData.UpdateRestoreRemark(entity).Result;
            string cacheKey = this.redisService.GetSingleRootKey(key, "goodsPurchaseId", requestDto.GoodsPurchaseId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<GoodsPurchaseDto>();
        }
        #endregion

        #region 修改采购停止备注信息
        public GoodsPurchaseDto UpdateStopRemark(GoodsPurchaseRemarkRequestDto requestDto)
        {
            if (!this.Exists(requestDto.GoodsPurchaseId))
            {
                throw new ArgumentException("此采购单不存在!");
            }
            var dto = this.Get(requestDto.GoodsPurchaseId);
            if (dto.PurchaseStatus == PurchaseStatusType.Stop)
            {
                throw new ArgumentException("此采购单已终止，无需重复操作!");
            }

            var entity = dto.As<GoodsPurchaseEntity>();
            entity.StopRemark = requestDto.Remark;
            var result = this.goodsPurchaseData.UpdateStopRemark(entity).Result;
            string cacheKey = this.redisService.GetSingleRootKey(key, "goodsPurchaseId", requestDto.GoodsPurchaseId);
            this.redisService.DeleteMultipleKey(cacheKey, false);
            this.redisService.DeleteMultipleKey(key, false);
            return result.As<GoodsPurchaseDto>();
        }
        #endregion
    }

}